/*
 * Implementierung des Tests von SimpleGameSprite
 *
 * @author   Benjamin Friedrich, Ken Dahm
 * @version  1.0  17.01.2009
 */
#include "GameSpriteTest.hpp"

typedef SimpleGameSprite::GameException Exception;

/**
 * Werden zur Konstrukion des "Muster"-Sprites und
 * zur Kontrolle von der Zustände von den SimpleGameSprite-
 * Instanzen genutzt.
 */
static const int SPRITE_X       = 60;
static const int SPRITE_Y       = 60;
static const int SPRITE_WIDTH   = 50;
static const int SPRITE_HEIGHT  = 50;
static const int SPRITE_STEP    = 10;


/*
 * Konstruktion des Muster-Sprites
 */
void GameSpriteTest::setUp()
{
	this->sprite = new SimpleGameSprite(SPRITE_X,  SPRITE_Y,  SPRITE_WIDTH,  SPRITE_HEIGHT,   SPRITE_STEP);
}

/*
 * Dekonstruktion des Muster-Sprites
 */
void GameSpriteTest::tearDown()
{
	delete this->sprite;
}


void GameSpriteTest::testConstructor()
{
	//-- Hier sollten GameExceptions geworfen werden
	CPPUNIT_ASSERT_THROW( SimpleGameSprite sprite( 1, 2, -3,  4,  5), Exception);
	CPPUNIT_ASSERT_THROW( SimpleGameSprite sprite( 1, 2,  3, -4,  5), Exception);
	CPPUNIT_ASSERT_THROW( SimpleGameSprite sprite( 1, 2,  3,  4, -5), Exception);

	//-- Hier sollte nichts geworfen werden
	CPPUNIT_ASSERT_NO_THROW( SimpleGameSprite sprite( 1, 2,  3,  4, 5));
}


void GameSpriteTest::testMoveLeft()
{
	/* Kopieren von Muster-Sprite, damit jede Testmethode unabhängig von
	   von der anderen testen kann. */
	SimpleGameSprite sprite(*this->sprite);

	sprite.moveLeft();

	/* CPPUNIT_ASSERT_EQUAL(a, b) bietet einen detailierten Report
	 * als CPPUNIT_ASSERT(a == b), wenn der Test schief läuft:
	 *
	 * CPPUNIT_ASSERT(a == b):
	 * -----------------------
	 * GameSpriteTest.cpp:76:Assertion
	 * Test name: GameSpriteTest::testMoveLeft
	 * assertion failed
	 * - Expression: a == b
	 *
	 * CPPUNIT_ASSERT_EQUAL(a, b):
	 * ---------------------------
	 * GameSpriteTest.cpp:66:Assertion
	 * Test name: GameSpriteTest::testMoveLeft
	 * equality assertion failed
	 * - Expected: 70
	 * - Actual  : 60
	 *
	 */
	CPPUNIT_ASSERT_EQUAL(sprite.sourceX, SPRITE_X - SPRITE_STEP);
	CPPUNIT_ASSERT_EQUAL(sprite.sourceY,      SPRITE_Y);
	CPPUNIT_ASSERT_EQUAL(sprite.destinationX, sprite.sourceX + SPRITE_WIDTH);
	CPPUNIT_ASSERT_EQUAL(sprite.destinationY, sprite.sourceY + SPRITE_HEIGHT);

	sprite.setAlive(false);
	CPPUNIT_ASSERT_THROW(sprite.moveLeft() ,Exception);

	sprite.setAlive(true);
	CPPUNIT_ASSERT_NO_THROW(sprite.moveLeft());
}

void GameSpriteTest::testMoveRight()
{
	SimpleGameSprite sprite(*this->sprite);
	sprite.moveRight();

	CPPUNIT_ASSERT_EQUAL(sprite.sourceX,      SPRITE_X + SPRITE_STEP );
	CPPUNIT_ASSERT_EQUAL(sprite.sourceY,      SPRITE_Y);
	CPPUNIT_ASSERT_EQUAL(sprite.destinationX, (sprite.sourceX + SPRITE_WIDTH) );
	CPPUNIT_ASSERT_EQUAL(sprite.destinationY, (sprite.sourceY + SPRITE_HEIGHT));

	sprite.setAlive(false);
	CPPUNIT_ASSERT_THROW(sprite.moveRight() ,Exception);

	sprite.setAlive(true);
	CPPUNIT_ASSERT_NO_THROW(sprite.moveRight());
}

void GameSpriteTest::testMoveUp()
{
	SimpleGameSprite sprite(*this->sprite);
	sprite.moveUp();


	CPPUNIT_ASSERT_EQUAL(sprite.sourceX, SPRITE_X);

	CPPUNIT_ASSERT_EQUAL(sprite.sourceY,      SPRITE_Y + SPRITE_STEP);
	CPPUNIT_ASSERT_EQUAL(sprite.destinationX, sprite.sourceX + SPRITE_WIDTH );
	CPPUNIT_ASSERT_EQUAL(sprite.destinationY, sprite.sourceY + SPRITE_HEIGHT);

	sprite.setAlive(false);
	CPPUNIT_ASSERT_THROW(sprite.moveUp() ,Exception);

	sprite.setAlive(true);
	CPPUNIT_ASSERT_NO_THROW(sprite.moveUp());
}

void GameSpriteTest::testMoveDown()
{
	SimpleGameSprite sprite(*this->sprite);
	sprite.moveDown();

	CPPUNIT_ASSERT_EQUAL(sprite.sourceX,      SPRITE_X );
	CPPUNIT_ASSERT_EQUAL(sprite.sourceY,      SPRITE_Y - SPRITE_STEP);
	CPPUNIT_ASSERT_EQUAL(sprite.destinationX, sprite.sourceX + SPRITE_WIDTH );
	CPPUNIT_ASSERT_EQUAL(sprite.destinationY, sprite.sourceY + SPRITE_HEIGHT);

	sprite.setAlive(false);
	CPPUNIT_ASSERT_THROW(sprite.moveDown() ,Exception);

	sprite.setAlive(true);
	CPPUNIT_ASSERT_NO_THROW(sprite.moveDown());
}


void GameSpriteTest::testHit()
{
	SimpleGameSprite hero (*this->sprite);
	SimpleGameSprite enemy(*this->sprite);

	CPPUNIT_ASSERT(enemy.hit(hero));

	hero.moveUp();
	CPPUNIT_ASSERT(enemy.hit(hero));

	for(int i = 0; i < 4; i++)
	{
		hero.moveUp();
	}

	//-- hero ist immer noch in Reichweite von enemy
	CPPUNIT_ASSERT( enemy.hit(hero));

	hero.moveUp(); //-- In Sicherheit
	CPPUNIT_ASSERT(! enemy.hit(hero));

	hero.moveDown(); //-- wieder in Gefahr
	for(int i = 0; i < 5; i++)
	{
		hero.moveRight();
	}
	CPPUNIT_ASSERT( enemy.hit(hero));

	hero.moveRight(); //-- in Sicherheit
	CPPUNIT_ASSERT(! enemy.hit(hero));

	for(int i = 0; i < 12; i++)
	{
		hero.moveLeft();
	}
	CPPUNIT_ASSERT(! enemy.hit(hero));

	hero.moveRight(); //-- in Gefahr
	CPPUNIT_ASSERT(enemy.hit(hero));

	for(int i = 0; i < 11; i++)
	{
		hero.moveDown();
	}
	CPPUNIT_ASSERT(! enemy.hit(hero));
}

bool GameSpriteTest::run()
{
	using namespace CppUnit;

	TestResult 				  result;
	TestResultCollector 	  collector;
	BriefTestProgressListener progress;
	TestRunner				  runner;
	CompilerOutputter 		  out(&collector, std::cout);

	result.addListener(&collector);
	result.addListener(&progress);

	runner.addTest(GameSpriteTest::suite());
	runner.run(result);

	out.write();

	return collector.wasSuccessful();
}


int main()
{
	GameSpriteTest test;
	return ! test.run();
}
